package com.quark.network.service.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.jspsmart.upload.File;
import com.jspsmart.upload.Files;
import com.jspsmart.upload.Request;
import com.jspsmart.upload.SmartUpload;
import com.jspsmart.upload.SmartUploadException;
import com.quark.framework.base.QuarkEnvironment;
import com.quark.framework.database.QuarkDBExecuteManager;
import com.quark.framework.database.QuarkDBExecuterFactory;
import com.quark.framework.utility.QuarkLog;
import com.quark.framework.utility.QuarkUtilDateHelper;
import com.quark.framework.utility.QuarkUtilHtmlEscape;
import com.quark.framework.utility.QuarkUtilStringTools;
import com.quark.web.ui.logic.QuarkUiLogicBase;
import com.quark.web.ui.logic.QuarkUiManager;

/**
 * Servlet implementation class QuarkServletUploadSerivce
 */
public class QuarkServletUploadService extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private static String uploadDir = "upload/";
	private static String uploadMultiplePrefix = "mu_";
	private static String uploadSinglePrefix = "si_";
	private static String uploadFieldInfoProperty = "property";
	private static String uploadFieldInfoReserved = "reserved";
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public QuarkServletUploadService() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		String message = "";
		String reqType = request.getParameter(QuarkEnvironment.paramAction);
		String reqClass = request.getParameter(QuarkEnvironment.paramClass);
		String reqKey = request.getParameter(QuarkEnvironment.paramPrimaryKey);
		String reqCharset = request.getParameter(QuarkEnvironment.paramCharset);
		String reqReturn = request.getParameter(QuarkEnvironment.paramReturn);
		String reqPage = request.getParameter(QuarkEnvironment.paramPageIndex);	
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put(QuarkEnvironment.paramCharset, reqCharset);
		paramMap.put(QuarkEnvironment.paramAction, reqType);
		paramMap.put(QuarkEnvironment.paramClass, reqClass);
		paramMap.put(QuarkEnvironment.paramPrimaryKey, reqKey);
		
		Boolean result = QuarkUiManager.getInstance().processUiSubmitData(paramMap, reqClass, reqType, paramMap);
		
		//store result
		request.getSession().setAttribute(QuarkEnvironment.paramSessionResult, result);		
		if(result == true)
		{
			message = QuarkEnvironment.errorSuccess;
		}
		else
		{
			message = QuarkEnvironment.errorProcess;
		}
		request.getSession().setAttribute(QuarkEnvironment.paramSessionMessage, message);
		
		//redirect
		response.sendRedirect(QuarkEnvironment.paramManagerPageName + "?" + QuarkEnvironment.paramClass + "=" + reqClass + "&" + QuarkEnvironment.paramPageIndex + "=" + (reqPage == null ? 0 : reqPage));
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		SmartUpload upload = new SmartUpload();
		String message = "";
		//Initialize
		upload.initialize(getServletConfig(), request, response);
		try {
			upload.upload();
		} catch (SmartUploadException e1) {
			// TODO Auto-generated catch block
			QuarkLog.log(e1);
			message = e1.getMessage();
			e1.printStackTrace();
		}
		
		Request uploadReq = upload.getRequest();
		//for debug
		Enumeration<?> names = uploadReq.getParameterNames();
		String debugString = "";
		while(names.hasMoreElements())
		{
			String name = names.nextElement().toString();
			debugString += name + ":{";
			String[] values = uploadReq.getParameterValues(name);
			for(int i = 0; i < values.length; i ++)
				debugString += values[i] + " ";
			debugString += "} ";
		}
		QuarkLog.println(debugString);
		//Get Parameters
		String reqType = uploadReq.getParameter(QuarkEnvironment.paramAction);
		String reqClass = uploadReq.getParameter(QuarkEnvironment.paramClass);
		String reqCharset = uploadReq.getParameter(QuarkEnvironment.paramCharset);
		String reqReturn = uploadReq.getParameter(QuarkEnvironment.paramReturn);
		String reqPage = uploadReq.getParameter(QuarkEnvironment.paramPageIndex);
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put(QuarkEnvironment.paramCharset, reqCharset);
		
		//Process Map
		debugString = "Processed {";
		Enumeration<?> paramNames = uploadReq.getParameterNames();
		Map<String, String> processedMap = new HashMap<String, String>();
		while(paramNames.hasMoreElements())
		{
			String name = (String) paramNames.nextElement();
			if(!isUploadField(name))
				//upload fields has two kind of parameter, 1 mu_propertyname_num contains file binary, 2 propertyName contains modify for old files
				//here blocks type 1
			{
				String unescaped = uploadReq.getParameter(name);
				/*
				try
				{
					unescaped = QuarkUtilHtmlEscape.unescape(unescaped);
				}
				catch(Exception e)
				{
					QuarkLog.logError(getClass().getName(), "unescape data failed," + e.getMessage());
				}
				*/
				debugString += name + ": " + unescaped;
				processedMap.put(name, unescaped);
			}
		}
		QuarkLog.logDebug(debugString + "}");

		//Process Upload File
		//upload file process:
		//file will be uploaded and saved as a temp file name, the file name will be merged into the PropertyName Field with seperater ';',
		//if the PropertyName field has old upload file modification information, it will be kept in front of the string
		//e.g 1,1;2,1;30;c:/windows/1.txt;c:/windows/2.txt
		try {
			String uploadTempPath = QuarkEnvironment.getInstance().getWorkingPath() + uploadDir;
			
			java.io.File dirFile = new java.io.File(uploadTempPath);
			if(!dirFile.exists())
			{
				if(!dirFile.mkdir())
				{
					QuarkLog.logError(getClass().getName(), "can't create temp upload dir!");
					message = QuarkEnvironment.errorCantCreateDir;
				}
			}
			//upload.save(uploadTempPath);
			
			Files uploadFiles = upload.getFiles();
			List<String> uploadFields = new ArrayList<String>();
			for(int i = 0; i < uploadFiles.getCount(); i ++)
			{
				File file = uploadFiles.getFile(i);
				if(QuarkUtilStringTools.isNullOrEmpty(file.getFileName()))
					continue;
				String strFileName = uploadTempPath + QuarkUtilDateHelper.getDateTimeString().replace(":", "").replace("-", "").replace(" ", "") + "_" + QuarkUtilStringTools.getRandomString(4) + "_" + file.getFileName().replace(";", "").replace(",", "");
				Map<String, String> fieldInfo = parseUploadFieldInfo(file.getFieldName());
				String field = fieldInfo.get(uploadFieldInfoProperty);
				field = field == null ? file.getFieldName() : field;
				if(!file.isMissing())
				{
					file.saveAs(strFileName);
					QuarkLog.logMessage("file " + strFileName + " in field " + field + " uploaded");
					String strOrg = "";
					
					if(!QuarkUtilStringTools.isNullOrEmpty(processedMap.get(field)))
					{
						strOrg = processedMap.get(field);
						strOrg += strOrg.endsWith(QuarkUtilStringTools.firstArraySplitor) ? "" : QuarkUtilStringTools.firstArraySplitor;
					}
					strOrg += strFileName;
					strOrg += QuarkUtilStringTools.firstArraySplitor;
					processedMap.put(field, strOrg);
					if(uploadFields.isEmpty() || !uploadFields.get(uploadFields.size() - 1).equals(field))
					{
						uploadFields.add(field); 
					}
				}
				else
				{
					QuarkLog.logError("can't upload " + strFileName + ", file missing");
					message = QuarkEnvironment.errorCantUpload;
				}
			}
			
			//remove ;
			for(Iterator<String> it = uploadFields.iterator(); it.hasNext();)
			{
				String key = it.next();
				String value = processedMap.get(key);
				if(value.endsWith(QuarkUtilStringTools.firstArraySplitor))
				{
					processedMap.put(key, value.substring(0, value.length() - 1));
				}
			}
		} catch (SmartUploadException e) {
			// TODO Auto-generated catch block
			QuarkLog.logError(getClass().getName(), "upload failed: " + e.getMessage());
			message = e.getMessage();
			e.printStackTrace();
		}
		
		//if it's copy, remove id
		boolean copy = reqType.equals(QuarkUiManager.submitCopy) ? true : false;
		if(copy)
		{
			processedMap.remove("id");
			reqType = QuarkUiManager.submitCreate;
		}
		//pass on request
		Boolean result = QuarkUiManager.getInstance().processUiSubmitData(processedMap, reqClass, reqType, paramMap);
		
		//store result
		request.getSession().setAttribute(QuarkEnvironment.paramSessionResult, result);		
		if(QuarkUtilStringTools.isNullOrEmpty(message) && result == true)
		{
			message = QuarkEnvironment.errorSuccess;
		}
		else
		{
			message = QuarkEnvironment.errorProcess;
		}
		request.getSession().setAttribute(QuarkEnvironment.paramSessionMessage, message);
		
		//redirect
		if(reqReturn != null)
			response.sendRedirect(QuarkUtilHtmlEscape.unescape(reqReturn));
		else
			response.sendRedirect(QuarkEnvironment.paramManagerPageName + "?" + QuarkEnvironment.paramClass + "=" + reqClass + "&" + QuarkEnvironment.paramPageIndex + "=" + (reqPage == null ? 0 : reqPage));
	}
	private Map<String, String> parseUploadFieldInfo(String uploadField)
	{
		Map<String, String> map = new HashMap<String, String>();
		String[] info = uploadField.split("-");
		if(info.length > 1)
		{
			map.put(uploadFieldInfoProperty, info[1]);
		}
		if(info.length > 2)
		{
			map.put(uploadFieldInfoReserved, info[2]);
		}
		
		return map;
	}
	
	private boolean isUploadField(String fieldName)
	{
		return (fieldName.startsWith(uploadSinglePrefix) || fieldName.startsWith(uploadMultiplePrefix));
	}
}
